函数类型
函数实际上是对象,因为每个函数都是Function这个构造函数的实例,具有Funtion构造函数定义的属性和方法。函数名实际上时指向函数对象的指针,说明这个问题,看如下代码:
function sum(a,b) {
return a + b;
}
// 相当于把sum的引用地址传递给sum2。
// 注意:不带圆括号的函数名是访问函数指针,而非调用函数
var sum2 = sum;
sum2(1,2) // 3
sum = null;
sum(2,3) // undefined // 将sum的内存回收,即sum的引用地址变了
sum2(2,3) //5 // 但sum2 还是指向原来的内存地址
1. 没有重载
理解了上面之后,重载相当于给函数变量重新修改了引用的值,因此后面会覆盖前面的,很容易理解了。
2.函数提升
其实和变量提升类似,就是声明型函数和表达式定义函数的区别,很简单
3.作为值的函数
因为函数名本身是变量,所以可以作为值进行传递,这里有一个很好的例子,也是一个很好的编程思想,如下:
function getSomeFunction(fn,arg) {
return fn(arg);
}
function add(num) {
return num + 10;
}
function getGreeting(name) {
return `Hello ${name}`;
}
getSomeFunction(add,5) // 15
getSomeFunction(getGreeting,'andy') // Hello andy
还可以从一个函数中返回另一个函数。例如我们在用数组的一些排序方法或者迭代方法的时候,因为传递进去的都是一个函数变量作为参数,所以这个参数我们可以用“外部函数返回函数”的方法进行编写,这样做的好处是,返回的函数可以把我们”特定想要规定”的参数传递进去进行计算,例如
// 规定利用哪个属性进行排序,如果不填则代表数组从大到小排序
function sortArgFuntion(compareProperty) { //compareProperty是上文中特定想要规定的参数
return function (val1, val2) {
if (compareProperty === undefined) { // 如果排序的是数组的值,则用常规的方法
if (val1 > val2) {
return 1;
} else if (val1 < val2) {
return -1;
} else {
return 0;
}
} else { // 如果排序的是对象的属性则用该方法
if (val1[compareProperty] > val2[compareProperty]) {
return 1;
} else if (val1[compareProperty] < val2[compareProperty]) {
return -1;
} else {
return 0;
}
}
}
}
var data = [{
name: 'andy',
age: 25
}, {
name: 'Nf',
age: 29
}]
data.sort(sortArgFuntion('name'))
sort函数的参数是个函数,用于将数组进行重排序。而我们将这个函数参数拿出来,就可以更直观的、复用性更高的去编写这个函数,达到我们想要的效果。同时需要仔细揣摩,理解函数返回函数的精髓和独到之处
4.函数内部属性
函数内部有两个特殊变量
- arguments
- this
arguments
是类数组对象,何为类数组对象呢?可以通过序号进行数组式的访问(如obj[1]),并且有length属性(对象你不定义length属性,是没有length的).类数组只有索引值和长度,没有数组的各种方法,所以如果要类数组调用数组的方法,就需要使用Array.prototype.method.call
来实现
this
this是JavaScript非常容易混淆和复杂的一个知识点,他代表什么完全取决于调用位置,我会但列出一篇总结this。e.g:
window.color = 'red';
var o = {color:"blue"};
function sayColor() {
console.log(this.color)
}
sayColor(); // red 因为调用位置是全局
o.sayColor = sayColor;
o.sayColor(); // blue 因为调用位置是o的对象里
从上面例子中我们要知道,函数名字仅仅是一个指针,虽然执行环境不同,全局的sayColor()和函数中的o.sayColor()指向的都是同一个函数
caller
es5新加的,他返回当前函数(必须是函数,对象不行)的调用环境,如果调用环境是全局,则返回null。有两种用法,一种是函数名加caller,一种是arguments.callee.caller
function outer() {
console.log(outer.caller); //null
inner();
};
function inner() {
console.log(inner.caller); // outer里的代码
}
5.函数的属性和方法
因为函数也是对象,所以也有属性和方法;函数里面有length和prototype两个属性,length指传入形参的个数function add(num1,num2) {} console.log(add.length) // 2
propertype(回头好好研究一番)
对于引用类型而言,propertype是保存所有实例方法的真正所在。在创建自定义引用类型以及实现继承,它的作用及其关键(到底多关键暂时还不太理解,尤其是继承这个词:)) es5中propertype不可枚举,因此不能遍历。
apply() 和 call()
两个参数,第一个参数是在哪个作用域运行,第二个参数apply是传入的Array或者arguments对象,call是传入每个值,其余他俩一模一样。这是其中一个例子,用来说明apply和call的作用:
var color = "red";
var o = {color:"blue"};
function sayColor() {
alert(this.color)
}
sayColor(); // red
sayColor.call(this); // red
sayColor.call(window); // red
sayColor.call(o); // blue
如果不用call的话我们需要这样做:
var color = "red";
var o = {color:"blue"};
function sayColor() {
alert(this.color)
}
o.sayColor = sayColor;
o.sayColor(); //blue
所以对比可以一目了然,call一个最大的作用是实现了对象和方法的解耦
bind方法
bind方法用来构建一个函数的实例,其this对象指向bind规定的作用域。e.g:
var color = "red";
var obj = {color:"blue"}
function sayColor() {
console.log(this.color);
}
var bindSayColor = sayColor.bind(obj);
bindSayColor(); // blue
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。